import datetime
import os
import subprocess
import sys
import time
from subprocess import getstatusoutput
import pandas as pd
import requests
import json
import numpy as np

token = "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"
headers = {'Authorization': f'token {token}'}


# headers = {}


def execute_cmd(cmd):
    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
    stdout, stderr = p.communicate()
    stderr = stderr.decode("utf-8")
    if stderr == '':
        stderr = 0
    stdout = stdout.decode("utf-8")
    # result = ""
    # for out in p.stdout.readlines():
    #     # todo fix sort error in command line (chinese characters)
    #     result += out.decode("utf-8")
    # code = 0
    return stderr, stdout


def run_cmd(cmd, path=None):
    """在指定目录执行命令，不改变当前工作目录

    :param cmd:
    :param path:
    :return:
    """
    # print('*' * 80)
    if not path:
        pass
        # print(f'path: {os.getcwd()}')
    else:
        # print(f'path: {path}')
        cmd = f'cd {path}& {cmd}'
    print(f'command: {cmd}')
    if not sys.platform.startswith('win'):
        cmd = cmd.replace('&', ';')
    # code, stdout = getstatusoutput(cmd)
    code, stdout = execute_cmd(cmd)
    # print('output:')
    lines = []
    for line in stdout.split('\n'):
        if line:
            # print(line)
            lines.append(line)
    assert code == 0, "\n" + "\n".join(lines)
    return lines


def call_fortify(repo_path, commit_hash=''):
    """
    执行fortify命令，进行扫描（如果有扫描结果，可以直接读取扫描结果，不用执行此命令）并生成包含IID,category,path,analyzer字段的csv文件
    :param repo_path: 项目目录
    :param commit_hash: 提交hash值
    :return: None
    """
    if not commit_hash:
        commit_hash = run_cmd('git rev-parse HEAD', repo_path)[0]
    proj_short_name = repo_path.split('/')[-1]
    pv_name = f'{proj_short_name}-{commit_hash}'
    fortify_results_dir = f'./scan/{proj_short_name}/java/{commit_hash}/fortify'
    if os.path.exists(f'{fortify_results_dir}/results.fpr'):
        return
    # 清除fortify在此版本上之前的build结果
    clean_cmd = f'sourceanalyzer.exe -b {pv_name} -clean'
    run_cmd(clean_cmd)
    # build：翻译java语言到fortify需要的中间语言
    build_cmd = f'sourceanalyzer.exe -b {pv_name} {repo_path}'
    run_cmd(build_cmd)
    # 对build结果进行扫描（耗时较长）
    if not os.path.exists(fortify_results_dir):
        os.makedirs(fortify_results_dir)
    scan_cmd = f'sourceanalyzer.exe -b {pv_name} -scan -f {fortify_results_dir}/results.fpr -Xmx6G'
    run_cmd(scan_cmd)
    # 对扫描结果生成总结报告
    csv_cmd = f'cmd.exe /C FPRUtility.bat -information -project {fortify_results_dir}/results.fpr -outputFormat CSV -f {fortify_results_dir}/summary.csv'
    run_cmd(csv_cmd)


def call_sourcemeter(repo_path, commit_hash=''):
    """调用SourceMeter扫描repo_path，由于SourceMeter的限制，项目放在本目录下的projects下

    :param repo_path: 项目目录
    :param commit_hash: 提交hash值
    :return: None
    """
    if not commit_hash:
        commit_hash = run_cmd('git rev-parse HEAD', repo_path)[0]
    proj_short_name = repo_path.split('/')[-1]
    scan_results_path = f'scan/{proj_short_name}/java/{commit_hash}/{proj_short_name}-Class.csv'
    # cleanProject=true 清除在目录中留下痕迹，避免影响git操作
    # *=false 关闭一些冗余功能
    if not os.path.exists(f'{scan_results_path}'):
        # args = ["/mnt/d/Downloads/SourceMeter-9.2.0-x64-Linux/Java/SourceMeterJava",
        args = ["D:/SourceMeter-9.2.0-x64-Windows/Java/SourceMeterJava.exe",
                f"-projectName={proj_short_name}",
                f"-projectBaseDir={repo_path}",
                f"-resultsDir=D:/code_and_results/scan",
                f'-currentDate="{commit_hash}"',
                "-cleanProject=true",
                '-runRTEHunter=false',
                '-runAndroidHunter=false',
                '-runMetricHunter=false',
                '-runVulnerabilityHunter=false',
                '-runFB=false',
                '-runUDM=false',
                '-runFaultHunter=false']
        cmd = " ".join(args)
        # 当前目录执行
        run_cmd(cmd)


def to_datetime(t):
    # 保留数字
    t = ''.join(list(filter(str.isdigit, t)))[:14]
    to_time_str = lambda t: time.strftime('%Y/%m/%d %H:%M:%S',
                                          time.strptime(t,
                                                        '%Y%m%d%H%M%S'))
    return datetime.datetime.strptime(to_time_str(t), '%Y/%m/%d %H:%M:%S')


def get_bugs_github(full_name):
    print('Getting bug records through github api ...')
    name = full_name.split('/')[-1]
    if not os.path.exists(f'bug2time/{name}_github.xlsx'):
        df = pd.DataFrame()
        i = 1
        while True:
            page_url = f'https://api.github.com/repos/{full_name}/issues?page={i}&per_page=100'
            print(f'page {i}: {page_url}')
            r = requests.get(
                page_url,
                # params={'labels': ['bug'], 'state': ['all']},
                params={'state': ['all'], 'is': ['issue'], 'labels': ['bug']},
                headers=headers
            )
            issues_of_page = json.loads(r.text)
            if len(issues_of_page) == 0:
                break
            for issue in issues_of_page:
                if 'pull_request' in issue.keys():
                    print('this is a pr')
                    continue
                # df = df.append([
                #     df,
                #     {'number': issue['number'],
                #      'time': to_datetime(issue['created_at']),
                #      'title': issue['title'],
                #      'close': issue['closed_at'],
                #      'labels': ', '.join([label['name'] for label in issue['labels']])
                #      }],
                #     ignore_index=True)
                df = pd.concat([df, pd.DataFrame([[issue['number'], to_datetime(issue['created_at']), issue['title'],
                                                   issue['closed_at'],
                                                   ', '.join([label['name'] for label in issue['labels']])]],
                                                 columns=['number', 'time', 'title', 'close', 'labels'])],
                               ignore_index=True)
            i = i + 1
        columns = ['number', 'time', 'title', 'close', 'labels']

        if not os.path.exists('bug2time'):
            os.mkdir('bug2time')
        df.to_excel(f'bug2time/{name}_github.xlsx', index=False, columns=columns, engine='xlsxwriter')
    return pd.read_excel(f'bug2time/{name}_github.xlsx')


if __name__ == '__main__':
    get_bugs_github('alibaba/easyexcel')
